pub mod error;
pub mod plist;
pub mod reader;

mod glyph;
pub use glyph::*;

use std::collections::BTreeMap;

use error::Error;
use plist::*;

#[derive(Debug, Clone, Default)]
pub struct Glyphs {
	app_version: Option<String>,
	format_version: u64,
	units_per_em: Option<i64>,
	metrics: Vec<Metrics>,
	family_name: String,
	date: Option<String>,
	copyright: Option<String>,
	designer: Option<String>,
	designer_url: Option<String>,
	manufacturer: Option<String>,
	manufacturer_url: Option<String>,
	version_major: Option<i64>,
	version_minor: Option<i64>,
	axes: Vec<Axis>,
	glyphs: Vec<Glyph>,
	font_master: Vec<FontMaster>,
	instances: Vec<Instance>,
	feature_prefixes: Vec<Feature>,
	features: Vec<Feature>,
	classes: Vec<Feature>,
	properties: Vec<Names>,
	kerning: BTreeMap<String, BTreeMap<String, BTreeMap<String, f64>>>,
	custom_parameters: Vec<CustomParameter>,
	numbers: Vec<NumberName>,
	user_data: BTreeMap<String, Value>,
}
impl Glyphs {
	pub fn load_pkg(base: impl AsRef<std::path::Path>) -> Result<Self, Error> {
		let fontinfo_file = base.as_ref().join("fontinfo.plist");
		let content = std::fs::read_to_string(fontinfo_file).map_err(|e| Error::Io(format!("{:?}", e)))?;
		Self::load_str(&content)
	}
	pub fn load_single(path: impl AsRef<std::path::Path>) -> Result<Self, Error> {
		let content = std::fs::read_to_string(path).map_err(|e| Error::Io(format!("{:?}", e)))?;
		Self::load_str(&content)
	}
	pub fn load_str(content: &str) -> Result<Self, Error> {
		let mut this = Self::default();
		let mut parse = plist::Parser::new(&content);
		match this.parse_info(&mut parse) {
			Ok(_) => Ok(this),
			Err(e) => {
				println!("{:?}", parse.pos());
				Err(e)
			}
		}
	}
	pub fn parse_info(&mut self, r: &mut plist::Parser<'_>) -> Result<(), Error> {
		r.expect(Event::Dictionary)?;
		while let Ok(token) = r.read_next() {
			match token {
				Event::End => break,
				Event::String(".appVersion") => self.app_version = r.parse()?,
				Event::String(".formatVersion") => self.format_version = r.parse()?,
				Event::String("familyName") => self.family_name = r.parse()?,
				Event::String("unitsPerEm") => self.units_per_em = r.parse()?,
				Event::String("versionMajor") => self.version_major = r.parse()?,
				Event::String("versionMinor") => self.version_minor = r.parse()?,
				Event::String("date") => self.date = r.parse()?,
				Event::String("copyright") => self.copyright = r.parse()?,
				Event::String("designer") => self.designer = r.parse()?,
				Event::String("designerURL") => self.designer_url = r.parse()?,
				Event::String("manufacturer") => self.manufacturer = r.parse()?,
				Event::String("manufacturerURL") => self.manufacturer_url = r.parse()?,
				//
				Event::String("axes") => self.axes = r.parse()?,
				Event::String("metrics") => self.metrics = r.parse()?,
				Event::String("properties") => self.properties = r.parse()?,
				Event::String("kerningLTR") => self.kerning = r.parse()?,
				Event::String("kerning") => self.kerning = r.parse()?,
				Event::String("numbers") => self.numbers = r.parse()?,
				//
				Event::String("featurePrefixes") => self.feature_prefixes = r.parse()?,
				Event::String("features") => self.features = r.parse()?,
				Event::String("classes") => self.classes = r.parse()?,
				//
				Event::String("glyphs") => self.glyphs = r.parse()?,
				//
				Event::String("fontMaster") => self.font_master = r.parse()?,
				Event::String("instances") => self.instances = r.parse()?,
				Event::String("customParameters") => self.custom_parameters = r.parse()?,
				Event::String("userData") => self.user_data = r.parse()?,
				//
				Event::String("stems") => _ = Value::from_plist(r)?,
				Event::String("settings") => _ = BTreeMap::<String, String>::from_plist(r)?,
				Event::String("disablesAutomaticAlignment") => _ = Value::from_plist(r)?,
				e => return Err(Error::unexpect(e)),
			}
		}
		Ok(())
	}
}

#[derive(Debug, Clone, Default)]
pub struct Axis {
	pub name: String,
	pub tag: String,
	pub hidden: Option<bool>,
}
impl FromPlist for Axis {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("name") => this.name = r.parse()?,
				Event::String("tag") => this.tag = r.parse()?,
				Event::String("Name") => this.name = r.parse()?,
				Event::String("Tag") => this.tag = r.parse()?,
				Event::String("hidden") => this.hidden = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
pub struct Metrics {
	pub type_: String,
	pub filter: String,
}
impl FromPlist for Metrics {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("type") => this.type_ = r.parse()?,
				Event::String("filter") => this.filter = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct CustomParameter {
	name: String,
	value: Option<Value>,
	disabled: Option<bool>,
}
impl FromPlist for CustomParameter {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("name") => this.name = r.parse()?,
				Event::String("disabled") => this.disabled = r.parse()?,
				Event::String("value") => this.value = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct NumberName {
	name: String,
}
impl FromPlist for NumberName {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("name") => this.name = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct Names {
	key: String,
	value: Option<String>,
	values: Vec<NameValue>,
}
impl FromPlist for Names {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("key") => this.key = r.parse()?,
				Event::String("value") => this.value = r.parse()?,
				Event::String("values") => this.values = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct NameValue {
	language: String,
	value: String,
}
impl FromPlist for NameValue {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("language") => this.language = r.parse()?,
				Event::String("value") => this.value = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct Feature {
	automatic: Option<i64>,
	disabled: Option<i64>,
	name: Option<String>,
	tag: Option<String>,
	notes: Option<String>,
	code: String,
	labels: Vec<NameValue>,
}
impl FromPlist for Feature {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("automatic") => this.automatic = r.parse()?,
				Event::String("disabled") => this.disabled = r.parse()?,
				Event::String("name") => this.name = r.parse()?,
				Event::String("tag") => this.tag = r.parse()?,
				Event::String("notes") => this.notes = r.parse()?,
				Event::String("code") => this.code = r.parse()?,
				Event::String("labels") => this.labels = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct Instance {
	name: String,
	exports: Option<i64>,
	active: Option<i64>,
	type_: Option<String>,
	axes_values: Vec<f64>,

	weight_value: Option<f64>,
	interpolation_weight: Option<f64>,

	width_value: Option<f64>,
	interpolation_width: Option<f64>,

	custom_value: Option<f64>,

	weight_class: Option<String>,
	width_class: Option<String>,
	properties: Vec<Names>,
	custom_parameters: Vec<CustomParameter>,
}
impl FromPlist for Instance {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("name") => this.name = r.parse()?,
				Event::String("exports") => this.exports = r.parse()?,
				Event::String("active") => this.active = r.parse()?,
				Event::String("type") => this.type_ = r.parse()?,
				Event::String("axesValues") => this.axes_values = r.parse()?,

				Event::String("weightValue") => this.weight_value = r.parse()?,
				Event::String("interpolationWeight") => this.interpolation_weight = r.parse()?,

				Event::String("widthValue") => this.width_value = r.parse()?,
				Event::String("interpolationWidth") => this.interpolation_width = r.parse()?,

				Event::String("customValue") => this.custom_value = r.parse()?,

				Event::String("weightClass") => this.weight_class = r.parse()?,
				Event::String("widthClass") => this.width_class = r.parse()?,
				Event::String("properties") => this.properties = r.parse()?,
				Event::String("customParameters") => this.custom_parameters = r.parse()?,

				Event::String("instanceInterpolations") => _ = BTreeMap::<String, Value>::from_plist(r)?,
				Event::String("isBold") => _ = bool::from_plist(r)?,
				Event::String("linkStyle") => _ = String::from_plist(r)?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct FontMaster {
	id: String,
	name: Option<String>,

	weight: Option<String>,
	width: Option<String>,
	custom: Option<String>,

	weight_value: Option<f64>,
	interpolation_weight: Option<f64>,

	width_value: Option<f64>,
	interpolation_width: Option<f64>,

	custom_value: Option<f64>,

	typo_ascender: Option<i64>,
	typo_descender: Option<f64>,
	typo_line_gap: Option<f64>,
	win_ascender: Option<f64>,
	win_descender: Option<f64>,

	axes_values: Vec<f64>,
	metric_values: Vec<Metric>, // v3

	ascender: Option<f64>,   // v2
	baseline: Option<f64>,   // v2
	descender: Option<f64>,  // v2
	cap_height: Option<f64>, // v2
	x_height: Option<f64>,   // v2
	// #[fromplist(alt_name = "italic angle")]
	italic_angle: Option<f64>, // v2

	alignment_zones: Vec<String>, // v2

	custom_parameters: Vec<CustomParameter>,
	number_values: Vec<f64>,
}
impl FromPlist for FontMaster {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("id") => this.id = r.parse()?,
				Event::String("name") => this.name = r.parse()?,

				Event::String("weight") => this.weight = r.parse()?,
				Event::String("width") => this.width = r.parse()?,
				Event::String("custom") => this.custom = r.parse()?,

				Event::String("weightValue") => this.weight_value = r.parse()?,
				Event::String("interpolationWeight") => this.interpolation_weight = r.parse()?,

				Event::String("widthValue") => this.width_value = r.parse()?,
				Event::String("interpolationWidth") => this.interpolation_width = r.parse()?,

				Event::String("customValue") => this.custom_value = r.parse()?,

				Event::String("typoAscender") => this.typo_ascender = r.parse()?,
				Event::String("typoDescender") => this.typo_descender = r.parse()?,
				Event::String("typoLineGap") => this.typo_line_gap = r.parse()?,
				Event::String("winAscender") => this.win_ascender = r.parse()?,
				Event::String("winDescender") => this.win_descender = r.parse()?,

				Event::String("axesValues") => this.axes_values = r.parse()?,
				Event::String("metricValues") => this.metric_values = r.parse()?,

				Event::String("ascender") => this.ascender = r.parse()?,
				Event::String("baseline") => this.baseline = r.parse()?,
				Event::String("descender") => this.descender = r.parse()?,
				Event::String("capHeight") => this.cap_height = r.parse()?,
				Event::String("xHeight") => this.x_height = r.parse()?,
				Event::String("italicAngle") => this.italic_angle = r.parse()?,
				Event::String("italic angle") => this.italic_angle = r.parse()?,

				Event::String("alignmentZones") => this.alignment_zones = r.parse()?,
				Event::String("customParameters") => this.custom_parameters = r.parse()?,
				Event::String("numberValues") => this.number_values = r.parse()?,

				Event::String("iconName") => _ = String::from_plist(r)?,
				Event::String("stemValues") => _ = Vec::<i64>::from_plist(r)?,
				Event::String("userData") => _ = BTreeMap::<String, Value>::from_plist(r)?,
				Event::String("guides") => _ = Value::from_plist(r)?,
				Event::String("glyphs") => _ = Value::from_plist(r)?,
				Event::String("visible") => _ = Value::from_plist(r)?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[derive(Debug, Clone, Default)]
struct Metric {
	pos: Option<f64>,
	over: Option<f64>,
}
impl FromPlist for Metric {
	fn from_plist(r: &mut Parser<'_>) -> Result<Self, Error> {
		r.expect(Event::Dictionary)?;
		let mut this = Self::default();
		loop {
			match r.read_next()? {
				Event::End => break,
				Event::String("pos") => this.pos = r.parse()?,
				Event::String("over") => this.over = r.parse()?,
				e => return Err(Error::Unexpect(format!("{:?}", e))),
			}
		}
		Ok(this)
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	#[test]
	fn test_load() {
		let _v = Glyphs::load_pkg("assets/fontc/glyphs3/infinity.glyphspackage").unwrap();
		println!("{:?}", _v);
	}
	#[test]
	fn load_glyps3() {
		let dir = std::fs::read_dir("assets/fontc/glyphs3").unwrap();
		for file in dir.flatten() {
			let path = file.path();
			if file.file_type().unwrap().is_file() && path.extension().and_then(|e| e.to_str()) == Some("glyphs") {
				println!("{}", path.display());
				Glyphs::load_single(&path).unwrap();
			}
		}
	}
	#[test]
	fn load_glyps2() {
		let dir = std::fs::read_dir("assets/fontc/glyphs2").unwrap();
		for file in dir.flatten() {
			let path = file.path();
			if file.file_type().unwrap().is_file() && path.extension().and_then(|e| e.to_str()) == Some("glyphs") {
				println!("{}", path.display());
				Glyphs::load_single(&path).unwrap();
			}
		}
	}
}
